﻿/**
 * jQuery Plugin mk (v0.3)
 * 
 * Copyright (c) Chris LaVoie (http://thelavoies.net/mkdemo.html)
 *
 * Dual licensed under the MIT and GPL licenses.
 *    MIT license: http://www.opensource.org/licenses/mit-license.php
 *    GPL license: http://www.opensource.org/licenses/gpl-3.0.html
 *
 * Summary:
 *    The mk plugin creates DOM elements wrapped as jQuery objects. The mk
 *    plugin also creates alias functions at the jQuery level for making
 *    elements, and has limited support for element creation templates.
 *    
 * Usage:
 *    $.mk(element)
 * 
 * Parameters:
 *    element - the string containing the name of the element to create
 *              (for example: 'a' for <a>, 'div' for a <div>, etc.).
 *
 *              The exceptions to this are for input elements. The following
 *              element names have special meaning to mk, they create <input/>
 *              elements with the value of the "type" attribute set to
 *              element:
 *                        button
 *                        checkbox
 *                        file 
 *                        hidden
 *                        image
 *                        password
 *                        radio
 *                        reset
 *                        submit
 *                        text
 *
 * Returns:
 *    A new node of the element specified wrapped as a jQuery object.
 *
 * Examples:
 *    var anchor = $.mk('a'); // an empty <a> element wrapped as a jQuery
 *                            // object.
 *        anchor = $('<a/>'); // equivalent to previous line
 *        anchor = $.mka();   // equivalent to previous two lines
 *
 *    var hidden = $('<input type="hidden"/>');
 *        hidden = $.mk('hidden');             // equivalent to previous line
 *        hidden = $.mkhidden();               // equivalent to previous lines
 */
(function($){
  // the initial list of known mk aliases and templates
  var mktypes = { a:          {},
                  abbr:       {},
                  acronym:    {},
                  address:    {},
                  applet:     {},
                  area:       {},
                  b:          {},
                  base:       {},
                  basefont:   {},
                  bdo:        {},
                  big:        {},
                  blockquote: {},
                  body:       {},
                  br:         {},
                  button:     {element:'input', attributes:{type:'button'}},
                  caption:    {},
                  center:     {},
                  checkbox:   {element:'input', attributes:{type:'checkbox'}},
                  cite:       {},
                  code:       {},
                  col:        {},
                  colgroup:   {},
                  dd:         {},
                  del:        {},
                  dfn:        {},
                  dir:        {},
                  div:        {},
                  dl:         {},
                  dt:         {},
                  em:         {},
                  fieldset:   {},
                  file:       {element:'input', attributes:{type:'file'}},
                  font:       {},
                  form:       {},
                  frame:      {},
                  frameset:   {},
                  h1:         {},
                  h2:         {},
                  h3:         {},
                  h4:         {},
                  h5:         {},
                  h6:         {},
                  head:       {},
                  hidden:     {element:'input', attributes:{type:'hidden'}},
                  hr:         {},
                  html:       {},
                  i:          {},
                  iframe:     {},
                  image:      {element:'input', attributes:{type:'image'}},
                  img:        {},
                  input:      {},
                  ins:        {},
                  isindex:    {},
                  kbd:        {},
                  label:      {},
                  legend:     {},
                  li:         {},
                  link:       {},
                  map:        {},
                  menu:       {},
                  meta:       {},
                  noframes:   {},
                  noscript:   {},
                  object:     {},
                  ol:         {},
                  optgroup:   {},
                  option:     {},
                  p:          {},
                  param:      {},
                  password:   {element:'input', attributes:{type:'password'}},
                  pre:        {},
                  q:          {},
                  radio:      {element:'input', attributes:{type:'radio'}},
                  reset:      {element:'input', attributes:{type:'reset'}},
                  s:          {},
                  samp:       {},
                  script:     {},
                  select:     {},
                  small:      {},
                  span:       {},
                  strike:     {},
                  strong:     {},
                  style:      {},
                  sub:        {},
                  submit:     {element:'input', attributes:{type:'submit'}},
                  sup:        {},
                  table:      {},
                  tbody:      {},
                  td:         {},
                  text:       {element:'input', attributes:{type:'text'}},
                  textarea:   {},
                  tfoot:      {},
                  th:         {},
                  thead:      {},
                  title:      {},
                  tr:         {},
                  tt:         {},
                  u:          {},
                  ul:         {}
  };  
  mktypes['var'] = {};
  // the main mk function
  function mk (element) {
    var options     = mktypes[element],
        newElement  = document.createElement(options         && 
                                             options.element ? options.element :
                                                               element),
        $newElement = $(newElement),
        key;
    if(options.attributes)
      for(key in options.attributes)
      {
        // if setting the 'type' attribute of the element use setAttribute() since
        // jQuery will raise an exception if using attr()
        if(key==='type')
          newElement.setAttribute(key,options.attributes[key]);
        // otherwise just use jQuery.attr()
        else
          $newElement.attr(key,options.attributes[key])
      }// end loop over new element attributes
    return $(newElement);
  };// $.mk()
  // add mk to jQuery
  $.extend({mk: mk});
  // adds a mk alias function to the jQuery object for each mk template
  function addMkAlias(templateName) {
    var extension                  = {};
    extension['mk' + templateName] = function(){return mk(templateName);};
    $.extend(extension);
  };// addMkAlias(element)
  // create alias mk functions to the jQuery object
  $.each(mktypes, addMkAlias);
  /**
   * Summary:
   *    The $.mk.set function allows creation or modification of $.mk
   *    element templates.
   *
   * Usage:
   *    $.mk.set(templateName, [elementName], [initialAttributes])
   *
   * Parameters:
   *    templateName      - the string containing the name of the template
   *
   *    elementName       - (optional) the string containing the name of the element
   *                        to create. If this parameter is not supplied the value 
   *                        of templateName is used in its place.
   *
   *    initialAttributes - (optional) an object containing all the initial
   *                        attributes the element will be created with.
   *
   * Returns:
   *    true if the template was set successfully, false otherwise.
   *
   * Examples:
   *    $.mk.set('a', {class:'highlight'});
   *    $.mk('a');                          // <a class="highlight" /> wrapped 
   *                                        // as a jQuery object
   *    $.mka();                            // equivalent to previosu line
   *
   *    $.mk.set('foo', 'form', {method: 'post'});
   *    $.mk('foo');                                // <form method="post" />
   *                                                // wrapped as jQuery object
   *    $.mkfoo();                                  // equivalent to previous line
   */
  mk.set = function(templateName) {
    // validate the template name
    if(typeof templateName !== 'string')
      return false;
    // create the template
    var template = {};
    if(typeof arguments[1] === 'string')
      template.element = arguments[1];
    if(typeof arguments[1] === 'object')
      template.attributes = arguments[1];
    if(typeof arguments[2] === 'object')
      template.attributes = arguments[2];
    // set the template
    mktypes[templateName] = template;
    // create the mk alias function for the template
    addMkAlias(templateName);
    return true;
  };// $.mk.set()
  /**
   * Summary:
   *    Gets information about a specific $.mk template, or all $.mk templates.
   *
   * Usage:
   *    $.mk.get([templateName])
   *
   * Parameters:
   *    templateName - (optional) the name of the template to retrieve.
   *
   * Returns:
   *    An object containing the details of $.mk template, or undefined
   *    if a template with the specified name does not exist. If 
   *    templateName is not specified an object is returned containing
   *    all $.mk templates.
   */
  mk.get = function() {
    // if a template name is given, return the specified template information
    if(arguments[0]) {
      if(mktypes[arguments[0]])
        return $.extend(true,{},mktypes[arguments[0]]);
      return mktypes[arguments[0]];
    }
    // return all templates
    return $.extend(true, {}, mktypes);
  };// $.mk.get()
})(jQuery);
